import proj4 from 'proj4'
import { fetchCoordinateSystemInfo, fetchCoordinateSystemBounds, fetchCoordinateSystemWKT } from '@/service'

/**
 * @description 根据输入的 EPSG Code 值获取 proj4 定义
 * @param {Number} epsgcode 坐标系EPSG Code值
 * @returns 非4326/3857坐标系返回 proj4 定义, 4326/3857坐标系直接返回code值
 */
export async function getCoordinateSystemProjInfo(epsgcode) {
  if ([4326, 3857].includes(epsgcode)) return epsgcode
  return await fetchCoordinateSystemInfo(epsgcode)
}

/**
 * @description 根据输入的 EPSG Code 值构造Leaflet中该坐标系定义代码
 * @param {Number} epsgcode 坐标系EPSG Code值
 * @returns Leaflet中坐标系定义代码
 */
export async function computedLeafletCRSDefined(epsgcode) {
  if ([4326, 3857].includes(epsgcode)) return `L.CRS.EPSG${epsgcode}`
  const otherCoordinateSystem = await fetchCoordinateSystemBounds(epsgcode)
  const computedBounds = await computedCoordinateSystemBounds(epsgcode, otherCoordinateSystem.bbox)
  const res = {
    CoordinateSystem: `EPSG:${otherCoordinateSystem.id.code}`,
    ...computedBounds
  }
  return `L.Proj.CRS('${res.CoordinateSystem}', {
    origin: L.point(${res.ProjectedBounds[0][0]}, ${res.ProjectedBounds[1][1]}),
    bounds: L.bounds([${res.ProjectedBounds[0][0]}, ${res.ProjectedBounds[0][1]}], [${res.ProjectedBounds[1][0]}, ${res.ProjectedBounds[1][1]}])
  })`
}

/**
 * @description 将输入坐标系的范围转换为4326坐标系的范围
 * @param {Array} boundingBox 坐标范围
 * @param {Number} epsgcode 输入坐标范围的坐标系EPSG Code值
 * @returns 4326坐标系的范围
 */
export async function coordinateConversion(boundingBox, epsgcode) {
  eval(await getCoordinateSystemProjInfo(epsgcode))
  const minxy = proj4(`EPSG:${epsgcode}`, 'EPSG:4326', [boundingBox[0][0], boundingBox[0][1]])
  const maxxy = proj4(`EPSG:${epsgcode}`, 'EPSG:4326', [boundingBox[1][0], boundingBox[1][1]])
  return [minxy, maxxy]
}

/**
 * @description 根据4326坐标系下的坐标范围计算出目标坐标系下的坐标范围, 中心点坐标, 以及投影坐标范围
 * @param {Number} epsgcode 坐标系EPSG Code值
 * @param {*} bbox 4326坐标系下的坐标范围
 * @returns 坐标范围, 中心点坐标, 以及投影坐标范围
 */
async function computedCoordinateSystemBounds(epsgcode, bbox) {
  eval(await getCoordinateSystemProjInfo(epsgcode))
  const LowerCorner = proj4('EPSG:4326', `EPSG:${epsgcode}`, [bbox.west_longitude, bbox.south_latitude])
  const UpperCorner = proj4('EPSG:4326', `EPSG:${epsgcode}`, [bbox.east_longitude, bbox.north_latitude])
  return {
    CenterCoordinates: [(LowerCorner[0] + UpperCorner[0]) / 2, (LowerCorner[1] + UpperCorner[1]) / 2],
    ProjectedBounds: [LowerCorner, UpperCorner],
    WGS84Bounds: [
      [bbox.west_longitude, bbox.south_latitude],
      [bbox.east_longitude, bbox.north_latitude]
    ]
  }
}

/**
 * @description 根据输入的 EPSG Code 值构造 Openlayers 中该坐标系定义代码
 * @param {Number} epsgcode 坐标系EPSG Code值
 * @param {string} [wmsType] WMS类型，1.1.1/1.3.0，默认值为1.1.1
 * @returns Openlayers中坐标系定义代码
 */
export async function computedOpenlayersCRSDefined(epsgcode, wmsType = '1.1.1') {
  if ([4326, 3857].includes(epsgcode)) return `EPSG:${epsgcode}`
  const otherCoordinateSystem = await fetchCoordinateSystemBounds(epsgcode)
  const computedBounds = await computedCoordinateSystemBounds(epsgcode, otherCoordinateSystem.bbox)
  const res = {
    CoordinateSystem: `EPSG:${otherCoordinateSystem.id.code}`,
    ...computedBounds
  }
  return `
  new Projection({
    code: '${res.CoordinateSystem}',
    extent: [${res.ProjectedBounds[0][0]}, ${res.ProjectedBounds[0][1]}, ${res.ProjectedBounds[1][0]}, ${res.ProjectedBounds[1][1]}],
    units: 'METER'${wmsType === '1.3.0' ? ",\n    axisOrientation: 'neu'" : ''}
  })`
}

/**
 * @description 根据坐标系EPSG Code值获取坐标系类型
 * @param {Number} epsgcode 坐标系EPSG Code值
 * @returns GEOGCS | PROJCS 分别表示地理坐标系还是投影坐标系
 */
export async function getCoordinateSystemType(epsgcode) {
  const match = JSON.stringify(epsgcode).match(/EPSG:(\d+)/)
  const epsgcodeValue = match ? parseInt(match[1], 10) : null
  if (epsgcodeValue < 2000 || epsgcodeValue > 9040) return
  if ([4326, 4490].includes(epsgcodeValue)) return 'GEOGCS'
  if (epsgcodeValue === 3857) return 'PROJCS'
  const crsWKT = await fetchCoordinateSystemWKT(epsgcodeValue)
  return crsWKT.startsWith('GEOGCS') ? 'GEOGCS' : 'PROJCS'
}
